

package com.hazelcast.jet.impl;

import com.hazelcast.jet.Job;

import javax.annotation.CheckReturnValue;

import static com.hazelcast.jet.impl.TerminationMode.ActionAfterTerminate.*;

public enum TerminationMode {

    // terminate and restart the job
    RESTART_GRACEFUL(true, RESTART), RESTART_FORCEFUL(false, RESTART),

    // terminate and mark the job as suspended
    SUSPEND_GRACEFUL(true, SUSPEND), SUSPEND_FORCEFUL(false, SUSPEND),

    // terminate and complete the job
    /**
     * Used to implement {@link Job#cancelAndExportSnapshot} in enterprise
     */
    CANCEL_GRACEFUL(true, CANCEL), CANCEL_FORCEFUL(false, CANCEL);

    private final boolean withTerminalSnapshot;
    private final ActionAfterTerminate actionAfterTerminate;

    TerminationMode(boolean withTerminalSnapshot, ActionAfterTerminate actionAfterTerminate) {
        this.withTerminalSnapshot = withTerminalSnapshot;
        this.actionAfterTerminate = actionAfterTerminate;
    }

    /**
     * If true, the job should be terminated with a terminal snapshot. If
     * false, it should be interrupted.
     */
    public boolean isWithTerminalSnapshot() {
        return withTerminalSnapshot;
    }

    /**
     * Returns the action that should be done after the job terminates.
     */
    public ActionAfterTerminate actionAfterTerminate() {
        return actionAfterTerminate;
    }

    /**
     * Returns a copy of this TerminationMode with terminal snapshot disabled.
     */
    @CheckReturnValue
    public TerminationMode withoutTerminalSnapshot() {
        TerminationMode res = this;
        if (this == CANCEL_GRACEFUL) {
            res = CANCEL_FORCEFUL;
        } else
            if (this == SUSPEND_GRACEFUL) {
                res = SUSPEND_FORCEFUL;
            } else
                if (this == RESTART_GRACEFUL) {
                    res = RESTART_FORCEFUL;
                }
        assert !res.isWithTerminalSnapshot() : "mode still has (withTerminalSnapshot == true): " + res;
        return res;
    }

    public enum ActionAfterTerminate {
        /**
         * Start the job again.
         */
        RESTART("Restart"),
        /**
         * Don't start the job again, mark the job as suspended.
         */
        SUSPEND("Suspend"),
        /**
         * Cancel the job.
         */
        CANCEL("Cancel");

        private final String description;

        ActionAfterTerminate(String description) {
            this.description = description;
        }

        public String description() {
            return description;
        }
    }
}
